package org.scs.carleton.ca.pgdt.core.internal.parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;

import org.scs.carleton.ca.pgdt.core.parser.nodes.IASTTranslationUnit;

/**
 * This is the physical representation of a translation unit
 * 
 * @author tessierj
 *
 */
public class ASTTranslationUnit implements IASTTranslationUnit {
	private static final String LINE_SEPARATOR = "\n"; //$NON-NLS-1$
	private ArrayList<Integer> offsetAtStartOfLine;
	private String source;
	
	public ASTTranslationUnit(String source) throws FileNotFoundException {
		offsetAtStartOfLine = new ArrayList<Integer>(40);
		this.source = source;
		
		BufferedReader bReader = null;
		StringReader sReader = null;
		//Now, populate the line length information
		try {
			sReader = new StringReader(source);
			bReader = new BufferedReader(sReader);
			
			String line = bReader.readLine();
			int currentOffset = 0;
			offsetAtStartOfLine.add(Integer.valueOf(currentOffset));
			
			while (line != null) {
				//Add the line length to the current offset (+2 for end of line characters)
				currentOffset += line.length() + 2;
				
				//Track the offset at the beginning of the line (line 1 = 0.  line 2 = line1Length + 2.  line 3 = line2 + line 1...
				offsetAtStartOfLine.add(Integer.valueOf(currentOffset));
				
				//Read the next line
				line = bReader.readLine();
			}
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			//Force the streams to close regardless of what happens.
			if (bReader != null) {
				try {
					bReader.close();
				}
				catch (Exception e) {
					//Stream couldn't close.  We can't do anything
				}
			}
			
			if (sReader != null) {
				try {
					sReader.close();
				}
				catch (Exception e) {
					//Stream couldn't close.  We can't do anything
				}
			}
		}
	}
	
	public ASTTranslationUnit(File theFile) throws FileNotFoundException {
		offsetAtStartOfLine = new ArrayList<Integer>(40);
		BufferedReader bReader = null;
		FileReader fReader = null;
		StringBuilder source = new StringBuilder();
		
		try {
			fReader = new FileReader(theFile);
			bReader = new BufferedReader(fReader);
			
			int currentCharAsInt = bReader.read();
			char currentChar;
			int currentOffset = 0;
			offsetAtStartOfLine.add(Integer.valueOf(currentOffset));
			boolean lastCharWasCarriage = false;
			
			while (currentCharAsInt != -1) {
				currentChar = (char) currentCharAsInt;

				++currentOffset;
				
				if (currentChar == '\r') {
					lastCharWasCarriage = true;
					offsetAtStartOfLine.add(Integer.valueOf(currentOffset));
				}
				else {
					if (currentChar == '\n') {
						if (lastCharWasCarriage) {
							offsetAtStartOfLine.remove(offsetAtStartOfLine.size() - 1);
						}
						offsetAtStartOfLine.add(Integer.valueOf(currentOffset));
					}
					lastCharWasCarriage = false;
				}
				
				source.append(currentChar);
				
				currentCharAsInt = bReader.read();
			}
			
//			
//			
//			String line = bReader.readLine();
//			int currentOffset = 0;
//			offsetAtStartOfLine.add(Integer.valueOf(currentOffset));
//			
//			while (line != null) {
//				//Build up the source code
//				source.append(line);
//				source.append(LINE_SEPARATOR);
//
//				//Add the line length to the current offset (+2 for end of line characters)
//				currentOffset += line.length() + 2;
//				
//				//Track the offset at the beginning of the line (line 1 = 0.  line 2 = line1Length + 2.  line 3 = line2 + line 1...
//				offsetAtStartOfLine.add(Integer.valueOf(currentOffset));
//				
//				//Read the next line
//				line = bReader.readLine();
//			}
			
			this.source = source.toString();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			//Force the streams to close regardless of what happens.
			if (bReader != null) {
				try {
					bReader.close();
				}
				catch (Exception e) {
					//Stream couldn't close.  We can't do anything
				}
			}
			
			if (fReader != null) {
				try {
					fReader.close();
				}
				catch (Exception e) {
					//Stream couldn't close.  We can't do anything
				}
			}
		}
	}

	/**
	 * Given a specific node location, determine the offset
	 * 
	 * @param location
	 * @return
	 */
	public int getOffset(int column, int line) {
		int offset = 0;
		
		if (line < offsetAtStartOfLine.size()) {
			//First determine the offset of the current line then add the column number.
			//If the token references line 0, it means line 1.  Line 1 is represented as 0 in the list.  (First element)
			offset = offsetAtStartOfLine.get((line == 0) ? line : line - 1) + column;
		}
		
		return offset;
	}

	public String getSource() {
		return source;
	}
}
